const kurento = require("kurento-client");
var mqtt = require('mqtt');
var path = require('path');
var fs = require('fs');
var format = require('string-format');
const e = require("express");
format.extend(String.prototype);


class TKmsObj {
    constructor() {
        this.kmsId = "";
        this.kmsType = "";
        this.key = "";
        this.parentKey = "";
        this.text = "";
        this.desc = "";
    }
}

class TKmsSvr {
    constructor() {
        this.config = {
            kmsUrl: "wss://wss.hhdata.cn:8433/kurento",
            tagKey: "tagKey-kms"
        }
        this.kmsClient = undefined;
        this.kmsObjs = {};
        this.kmsObjsByKey = {};
        this.tasks = [{
            kmsId: "",
            kmsType: "MediaPipeline",
            key: "c001",
            text: "数字急救系统",
            parentKey: "",
            desc: "数字急救系统 , 智慧120系统"
        }, {
            kmsId: "",
            kmsType: "Dispatcher",
            key: "c001/hub01",
            text: "浙E23456",
            parentKey: "c001",
            desc: ""
        }, {
            kmsId: "",
            kmsType: "HubPort",
            key: "c001/hub01/p01",
            text: "司机",
            parentKey: "c001/hub01",
            desc: ""
        }, {
            kmsId: "",
            kmsType: "HubPort",
            key: "c001/hub01/p02",
            text: "医院",
            parentKey: "c001/hub01",
            desc: ""
        }, {
            kmsId: "",
            kmsType: "HubPort",
            key: "c001/hub01/p03",
            text: "后舱",
            parentKey: "c001/hub01",
            desc: ""
        }, {
            kmsId: "",
            kmsType: "AlphaBlending",
            key: "c001/alpha01",
            text: "组合-医生",
            parentKey: "c001",
            desc: ""
        }, {
            kmsId: "",
            kmsType: "HubPort",
            key: "c001/alpha01/v00",
            text: "主窗口",
            parentKey: "c001/alpha01",
            desc: ""
        }, {
            kmsId: "",
            kmsType: "HubPort",
            key: "c001/alpha01/v01",
            text: "子窗口-01",
            parentKey: "c001/alpha01",
            desc: ""
        }, {
            kmsId: "",
            kmsType: "HubPort",
            key: "c001/alpha01/v02",
            text: "子窗口-02",
            parentKey: "c001/alpha01",
            desc: ""
        }, {
            kmsId: "",
            kmsType: "HubPort",
            key: "c001/alpha01/out",
            text: "输出窗口",
            parentKey: "c001/alpha01",
            desc: ""
        }, {
            kmsId: "",
            kmsType: "Dispatcher",
            key: "c001/hub02",
            text: "浙E12345",
            parentKey: "c001",
            desc: ""
        }, {
            kmsId: "",
            kmsType: "MediaPipeline",
            key: "c002",
            text: "智能家居系统",
            parentKey: "",
            desc: "智能家居系统 , 可视对讲110"
        }, {
            kmsId: "",
            kmsType: "MediaPipeline",
            key: "c003",
            text: "远程游戏",
            parentKey: "",
            desc: "远程游戏系统 , 体彩游戏"
        }, {
            kmsId: "",
            kmsType: "Dispatcher",
            key: "c003/hub01",
            text: "王者1组",
            parentKey: "c003",
            desc: ""
        }, {
            kmsId: "",
            kmsType: "Dispatcher",
            key: "c003/hub02",
            text: "王者2组",
            parentKey: "c003",
            desc: ""
        }];
        this.connectionPorts = [
            { h: "c001/hub01", s: "c001/hub01/p01", t: "c001/hub01/p02" },
            { h: "c001/hub01", s: "c001/hub01/p01", t: "c001/hub01/p03" },
        ];
        this.alphaConfigs = [{
            alphaKey: "c001/alpha01",
            masterPort: "c001/alpha01/v00",
            items: [
                //{ key: "c001/alpha01/v00", zOrder: 1, left: 0, top: 0, width: 1, height: 1 },
                { key: "c001/alpha01/v01", zOrder: 2, left: 0, top: 0, width: 0.2, height: 0.2 },
                { key: "c001/alpha01/v02", zOrder: 3, left: 0.4, top: 0, width: 0.2, height: 0.2 },
            ]
        }]
    }
    getClient() {
        var me = this;
        return new Promise((success, faild) => {
            try {
                if (me.kmsClient && me.kmsClient != null) {
                    success(me.kmsClient);
                } else {
                    kurento(me.config.kmsUrl, function(erClient, _client) {
                        me.kmsClient = _client;
                        _client.on('disconnect', function() {
                            delete me["kmsClient"];
                        })
                        _client.getServerManager().then(_svr => {
                            _client.svr = _svr;
                            _svr.on('ObjectDestroyed', (data => {
                                if (me.kmsObjs[data.objectId]) {
                                    var obj = me.kmsObjs[data.objectId];
                                    var key = obj.task.key;
                                    delete me.kmsObjs[data.objectId];
                                    delete me.kmsObjsByKey[key];
                                    //notify to mqtt
                                }
                            }));
                            _svr.getTags().then(ds => {
                                success(me.kmsClient);
                            })
                        })
                    })
                }
            } catch (er) {
                console.log(er);
                success();
            }
        })
    }
    reset() {
        var me = this;
        return new Promise((success, faild) => {
            try {
                me.getClient().then(_client => {
                    return _client.svr.getPipelines();
                }).then(ps => {
                    var free = () => {
                        if (ps.length > 0) {
                            var p = ps.shift();
                            p.release().then(_ => {
                                free();
                            })
                        } else {
                            success();
                        }
                    }
                    free();
                })
            } catch (er) {
                console.log(er);
                success();
            }
        })
    }
    scanKmsObjs() {
        var me = this;
        return new Promise((success, faild) => {
            try {
                me.getClient().then(_client => {
                    return _client.svr.getPipelines();
                }).then(pipes => {

                    var assignKmsObj = (obj) => {
                        return new Promise((s, f) => {
                            me.kmsObjs[obj.id] = obj;
                            obj.getTags().then(_tags => {
                                console.log(_tags);
                                var arrs = _tags.filter(t => {
                                    return t.key == me.config.tagKey;
                                });
                                if (arrs.length > 0) {
                                    var infoJson = arrs[0].value;
                                    var task = JSON.parse(infoJson);
                                    obj.task = task;
                                    task.kmsId = obj.id;
                                    me.kmsObjsByKey[obj.task.key] = obj;
                                    obj.getChildren().then(childObjs => {
                                        var loadChild = function() {
                                            if (childObjs.length > 0) {
                                                var childObj = childObjs.shift();
                                                assignKmsObj(childObj).then(_ => {
                                                    loadChild();
                                                })
                                            } else {
                                                s();
                                            }
                                        }
                                        loadChild();
                                    });
                                } else {
                                    s();
                                }
                            });

                        });
                    }
                    var loadpipe = () => {
                        if (pipes.length > 0) {
                            var pipe = pipes.shift();
                            assignKmsObj(pipe).then(_ => {
                                loadpipe();
                            })
                        } else {
                            success();
                        }
                    }
                    loadpipe();
                })

            } catch (er) {
                console.log(er);
                success();
            }
        })
    }
    loadTaskObjs() {
        var me = this;
        return new Promise((success, faild) => {
            try {
                me.reset().then(_ => {
                    return me.scanKmsObjs();
                }).then(_ => {
                    return me.loadPipes();
                }).then(_ => {
                    return me.loadDispatchers();
                }).then(_ => {
                    return me.loadAlphaLayer();
                }).then(_ => {
                    return me.loadHubPorts();
                }).then(_ => {
                    return me.connectPorts();
                }).then(_ => {
                    return me.setAlphaTasks();
                }).then(_ => {
                    success();
                })
            } catch (er) {
                console.log(er);
                success();
            }
        })
    }
    loadPipes() {
        var me = this;
        return new Promise((success, faild) => {
            try {
                var items = me.tasks.filter(t => {
                    return t.kmsType == "MediaPipeline";
                })
                var createPipe = (pipeTask) => {
                    return new Promise((s, f) => {
                        me.kmsClient.create("MediaPipeline").then(pipe => {
                            pipeTask.kmsId = pipe.id;
                            pipe.task = pipeTask;
                            me.kmsObjs[pipe.id] = pipe;
                            me.kmsObjsByKey[pipeTask.key] = pipe;
                            return pipe.addTag(me.config.tagKey, JSON.stringify(pipeTask));
                        }).then(_ => {
                            s();
                        })
                    })
                }
                var loadItem = function() {
                    if (items.length > 0) {
                        var item = items.shift();
                        if (me.kmsObjsByKey[item.key]) {
                            item.kmsId = me.kmsObjsByKey[item.key].id;
                            loadItem();
                        } else {
                            createPipe(item).then(_ => {
                                loadItem();
                            })
                        }
                    } else {
                        success();
                    }
                }
                loadItem();

            } catch (er) {
                console.log(er);
                success();
            }
        })
    }
    loadDispatchers() {
        var me = this;
        return new Promise((success, faild) => {
            try {
                var items = me.tasks.filter(t => {
                    return t.kmsType == "Dispatcher";
                })
                var createDispatcher = (task) => {
                    return new Promise((s, f) => {
                        var pipe = me.kmsObjsByKey[task.parentKey];
                        if (pipe && pipe != null) {
                            pipe.create("Dispatcher").then(obj => {
                                task.kmsId = obj.id;
                                obj.task = task;
                                me.kmsObjs[obj.id] = obj;
                                me.kmsObjsByKey[task.key] = obj;
                                return obj.addTag(me.config.tagKey, JSON.stringify(task));
                            }).then(_ => {
                                s();
                            })
                        } else {
                            s();
                        }

                    })
                }
                var loadItem = function() {
                    if (items.length > 0) {
                        var item = items.shift();
                        if (me.kmsObjsByKey[item.key]) {
                            item.kmsId = me.kmsObjsByKey[item.key].id;
                            loadItem();
                        } else {
                            createDispatcher(item).then(_ => {
                                loadItem();
                            })
                        }
                    } else {
                        success();
                    }
                }
                loadItem();

            } catch (er) {
                console.log(er);
                success();
            }
        })
    }
    loadHubPorts() {
        var me = this;
        return new Promise((success, faild) => {
            try {
                var items = me.tasks.filter(t => {
                    return t.kmsType == "HubPort";
                })
                var createHubPort = (task) => {
                    return new Promise((s, f) => {
                        var hub = me.kmsObjsByKey[task.parentKey];
                        if (hub && hub != null) {
                            hub.createHubPort().then(obj => {
                                task.kmsId = obj.id;
                                obj.task = task;
                                me.kmsObjs[obj.id] = obj;
                                me.kmsObjsByKey[task.key] = obj;
                                return obj.addTag(me.config.tagKey, JSON.stringify(task));
                            }).then(_ => {
                                s();
                            })
                        } else {
                            s();
                        }

                    })
                }
                var loadItem = function() {
                    if (items.length > 0) {
                        var item = items.shift();
                        if (me.kmsObjsByKey[item.key]) {
                            item.kmsId = me.kmsObjsByKey[item.key].id;
                            loadItem();
                        } else {
                            createHubPort(item).then(_ => {
                                loadItem();
                            })
                        }
                    } else {
                        success();
                    }
                }
                loadItem();

            } catch (er) {
                console.log(er);
                success();
            }
        })
    }
    loadAlphaLayer() {
        var me = this;
        return new Promise((success, faild) => {
            try {
                var items = me.tasks.filter(t => {
                    return t.kmsType == "AlphaBlending";
                })
                var createAlphaLayer = (task) => {
                    return new Promise((s, f) => {
                        var pipe = me.kmsObjsByKey[task.parentKey];
                        if (pipe && pipe != null) {
                            pipe.create("AlphaBlending").then(obj => {
                                task.kmsId = obj.id;
                                obj.task = task;
                                me.kmsObjs[obj.id] = obj;
                                me.kmsObjsByKey[task.key] = obj;
                                return obj.addTag(me.config.tagKey, JSON.stringify(task));
                            }).then(_ => {
                                s();
                            })
                        } else {
                            s();
                        }

                    })
                }
                var loadItem = function() {
                    if (items.length > 0) {
                        var item = items.shift();
                        if (me.kmsObjsByKey[item.key]) {
                            item.kmsId = me.kmsObjsByKey[item.key].id;
                            loadItem();
                        } else {
                            createAlphaLayer(item).then(_ => {
                                loadItem();
                            })
                        }
                    } else {
                        success();
                    }
                }
                loadItem();

            } catch (er) {
                console.log(er);
                success();
            }
        })
    }
    connectPorts() {
        var me = this;
        return new Promise((success, faild) => {
            try {
                var items = JSON.parse(JSON.stringify(me.connectionPorts));
                var loadItem = function() {
                    if (items.length > 0) {
                        var item = items.shift();
                        var hub = me.kmsObjsByKey[item.h];
                        var src = me.kmsObjsByKey[item.s];
                        var target = me.kmsObjsByKey[item.t];
                        if (hub && src && target) {
                            hub.connect(src, target).then(_ => {
                                loadItem();
                            })
                        } else {
                            loadItem();
                        }
                    } else {
                        success();
                    }
                }
                loadItem();
            } catch (er) {
                console.log(er);
                success();
            }
        })
    }
    setAlphaLayer(alphaConfig) {
        var me = this;
        return new Promise((success, faild) => {
            try {
                var hub = me.kmsObjsByKey[alphaConfig.alphaKey];
                var masterPort = me.kmsObjsByKey[alphaConfig.masterPort];
                hub.setMaster(masterPort.id, 1).then(_ => {
                    var items = JSON.parse(JSON.stringify(alphaConfig.items));
                    var setItemLayer = function() {
                        if (items.length > 0) {
                            var item = items.shift();
                            var port = me.kmsObjsByKey[item.key];
                            hub.setPortProperties(1.0 * item.left, 1.0 * item.top, item.zOrder, 1.0 * item.width, 1.0 * item.height, port.id, function(err) {
                                console.log(err);
                                setItemLayer();
                            });
                        } else {
                            success();
                        }
                    }
                    setItemLayer();
                })
            } catch (er) {
                console.log(er);
                success();
            }
        })
    }
    setAlphaTasks() {
        var me = this;
        return new Promise((success, faild) => {
            try {
                var items = JSON.parse(JSON.stringify(me.alphaConfigs));
                var setItem = function() {
                    if (items.length > 0) {
                        var item = items.shift();
                        me.setAlphaLayer(item).then(_ => {
                            setItem();
                        })
                    } else {
                        success();
                    }
                }
                setItem();
            } catch (er) {
                console.log(er);
                success();
            }
        })
    }
    regist2WebSvr(webSvr) {
        var me = this;
        if (webSvr && webSvr != null && webSvr.registRoute) {
            var respJson = function(result, response) {
                try {
                    response.send(JSON.stringify(result));
                } catch (eer) {
                    console.log(eer);
                }
            }
            webSvr.registRoute("kms", "kms", "getKmsObjs", function(result, request, response) {
                try {
                    var res = {};
                    Object.keys(me.kmsObjsByKey).forEach(key => {
                        res[key] = me.kmsObjsByKey[key].task;
                    });
                    result.data = res;
                    respJson(result, response);
                } catch (err) {
                    console.log(err);
                    respJson(result, response);
                }
            });
            webSvr.registRoute("kms", "kms", "getKmsObjByKey", function(result, request, response) {
                try {
                    var keys = Object.keys(me.kmsObjsByKey).filter(key => {
                        return key == result.ps.key;
                    });
                    result.data = keys.length > 0 ? me.kmsObjsByKey[keys[0]] : {};
                    respJson(result, response);
                } catch (err) {
                    console.log(err);
                    respJson(result, response);
                }
            });
            webSvr.registRoute("kms", "kms", "connectHubPort", function(result, request, response) {
                try {
                    var hubKey = result.ps.hubKey;
                    var srcKey = result.ps.srcKey;
                    var targetKey = result.ps.targetKey;
                    var hub = me.kmsObjsByKey[hubKey];
                    var srcPort = me.kmsObjsByKey[srcKey];
                    var targetPort = me.kmsObjsByKey[targetKey];
                    if (hub && srcPort && targetPort) {
                        hub.connect(srcPort, targetPort).then(_ => {
                            result.data = {
                                status: 1
                            };
                            respJson(result, response);
                        })
                    } else {
                        result.error = "key is error";
                        respJson(result, response);
                    }
                } catch (err) {
                    console.log(err);
                    respJson(result, response);
                }
            });
        }
    }
}
module.exports = {
    TKmsSvr: TKmsSvr
};
/*
var kms = new TKmsSvr();
kms.loadTaskObjs().then(_ => {
    console.log('end', kms)
})
*/